using System;
using System.Web.Mvc;
using System.Xml.Serialization;
using System.Reflection;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Script.Serialization;

namespace MvcImproved.Xml
{
	/// <summary>
	/// Action result that serializes the specified object into XML and outputs it to the response stream.
	/// <example>
	/// <![CDATA[
	/// public XmlResult AsXml() {
	///		List<Person> people = _peopleService.GetPeople();
	///		return new XmlResult(people);
	/// }
	/// ]]>
	/// </example>
	/// </summary>
	public class XmlResult : ActionResult
	{
		private object _objectToSerialize;
		public bool DefaultIgnore
		{
			get;
			set;
		}

		/// <summary>
		/// Creates a new instance of the XmlResult class.
		/// </summary>
		/// <param name="objectToSerialize">The object to serialize to XML.</param>
		public XmlResult(object objectToSerialize, bool defaultIgnore)
		{
			_objectToSerialize = objectToSerialize;
			DefaultIgnore = defaultIgnore;
		}

		public XmlResult(object objectToSerialize)
			: this(objectToSerialize, true)
		{
		}

		/// <summary>
		/// The object to be serialized to XML.
		/// </summary>
		public object ObjectToSerialize
		{
			get { return _objectToSerialize; }
		}

		private Dictionary<System.Type, System.Type> _SerializeProperties = new Dictionary<Type, Type>();
		public Dictionary<System.Type, System.Type> SerializeTypeOverride
		{
			get
			{
				return _SerializeProperties;
			}
		}

		public static JavaScriptSerializer Serializer = new JavaScriptSerializer();
		public enum StringFormatting
		{
			Normal,
			Escaped
		}

		public System.Xml.XmlWriterSettings WriterSettings
		{
			get
			{
				return new System.Xml.XmlWriterSettings() { Indent = false, Encoding = System.Text.Encoding.UTF8, CloseOutput = false };
			}
		}

		public string ToString(StringFormatting format)
		{
			if (_objectToSerialize != null)
			{
				System.Text.StringBuilder sb = new System.Text.StringBuilder();

				var xs = new MvcXmlSerializer(_objectToSerialize.GetType());
				foreach (var pair in SerializeTypeOverride)
				{
					xs.SerializeTypeOverride.Add(pair.Key, pair.Value);
				}
				xs.Serialize(System.Xml.XmlWriter.Create(sb, WriterSettings), _objectToSerialize);

				if (format == StringFormatting.Normal)
					return sb.ToString();
				else
					return Serializer.Serialize(sb.ToString());
			}

			return null;
		}

		public override string ToString()
		{
			return ToString(StringFormatting.Normal);
		}

		/// <summary>
		/// Serialises the object that was passed into the constructor to XML and writes the corresponding XML to the result stream.
		/// </summary>
		/// <param name="context">The controller context for the current request.</param>
		public override void ExecuteResult(ControllerContext context)
		{
			if (_objectToSerialize != null)
			{
				var xs = new MvcXmlSerializer(_objectToSerialize.GetType());
				foreach (var pair in SerializeTypeOverride)
				{
					xs.SerializeTypeOverride.Add(pair.Key, pair.Value);
				}
				context.HttpContext.Response.ContentType = "text/xml";
				xs.Serialize(System.Xml.XmlWriter.Create(context.HttpContext.Response.Output, WriterSettings), _objectToSerialize);
			}
		}
	}
}
